package main;

import items.Item;

import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;

import entities.NPC;
import entities.Player;

import blocks.Block;
import blocks.EarthBlock;
import blocks.GrassBlock;
import blocks.StoneBlock;


import shared.Grid;

public class Map {
	private static HashMap<String, Block> blockMap;
	private static ArrayList<Item> itemList;
	private static ArrayList<NPC> npcList;
	private static int itemIndexCounter;
	private static int playerPosX;
	private static int playerPosY;
	private static int minX, maxX;
	private static int minY, maxY;
	
	//Blocks
	private static int stoneChance;
	
	public static void init() {
		blockMap = new HashMap<String, Block>();
		itemList = new ArrayList<Item>();
		npcList = new ArrayList<NPC>();
		itemIndexCounter = 0;
		minX = -100;
		maxX = 100;
		minY = 5;
		maxY = 205;
		
		//Blocks
		stoneChance = 5;
	}

	public static void addBlock(int x, int y, String blockType) throws SlickException {
		Point p = Grid.calculateGridPosition(x, y);
		Block b = null;
		
		if(blockType.equals("earth"))
			b = new EarthBlock((int)p.getX(), (int)p.getY(), Grid.getSize(), Grid.getSize());
		if(blockType.equals("grass"))
			b = new GrassBlock((int)p.getX(), (int)p.getY(), Grid.getSize(), Grid.getSize());
		if(blockType.equals("stone"))
			b = new StoneBlock((int)p.getX(), (int)p.getY(), Grid.getSize(), Grid.getSize());
		
		if(b != null)
			blockMap.put("x" + (int)p.getX() + "y" + (int)p.getY(), b);
	}
	
	public static Block getBlock(int x, int y) {
		Point p = Grid.calculateGridPosition(x, y);
		return blockMap.get("x" + (int)p.getX() + "y" + (int)p.getY());
	}
	
	public static void removeBlock(int x, int y) {
		Point p = Grid.calculateGridPosition(x, y);
		blockMap.remove("x" + (int)p.getX() + "y" + (int)p.getY());
	}
	
	public static void update(Player player) throws SlickException {
		playerPosX = player.getX() + player.getWidth()/2;
		playerPosY = player.getY() + player.getHeight()/2;
		
		for(int i = 0; i < itemList.size(); i++) {
			itemList.get(i).update();
		}
		
		for(int i = 0; i < npcList.size(); i++) {
			npcList.get(i).update(player);
			if(!npcList.get(i).isAlive()) {
				npcList.remove(i);
			}
		}
	}

	public static void draw(GameContainer gc, Graphics g) {
		int startX = playerPosX - FoxMain.getWidth()/2;
		int startY = playerPosY - FoxMain.getHeight()/2;
		
		for(int i = startX - Grid.getSize(); i < FoxMain.getWidth() + startX + Grid.getSize()*2; i += Grid.getSize()) {
			for(int j = startY; j < FoxMain.getHeight() + startY + Grid.getSize(); j += Grid.getSize()) {
				Block b = getBlock(i, j);
				
				if(b != null) {
					b.draw(gc, g);
				}
			}
		}
		
		for(int i = 0; i < itemList.size(); i++) {
			itemList.get(i).draw(g);
		}
		
		for(int i = 0; i < npcList.size(); i++) {
			npcList.get(i).draw(gc, g);
		}
	}
	
	public static void generateRandomMap(int minX, int maxX, int minY, int maxY) throws SlickException {
		Random r = new Random();
		
		//Initial Placing
		for(int i = minX; i < maxX; i++) {
			for(int j = minY; j < maxY; j++) {
				//left + above
				if(getBlock(i * Grid.getSize(), (j-1) * Grid.getSize()) != null &&
						getBlock((i-1) * Grid.getSize(), (j-1) * Grid.getSize()) != null) {
					addBlock(i * Grid.getSize(), j * Grid.getSize(), "earth");
				//right + above
				} else if(getBlock(i * Grid.getSize(), (j-1) * Grid.getSize()) != null &&
						getBlock((i+1) * Grid.getSize(), (j-1) * Grid.getSize()) != null) {
					addBlock(i * Grid.getSize(), j * Grid.getSize(), "earth");
				//above	
				} else if(getBlock(i * Grid.getSize(), (j-1) * Grid.getSize()) != null) {
					addBlock(i * Grid.getSize(), j * Grid.getSize(), "earth");
				//left + right	
				} else if(getBlock((i+1) * Grid.getSize(), (j) * Grid.getSize()) != null &&
						getBlock((i-1) * Grid.getSize(), (j) * Grid.getSize()) != null) {
					addBlock(i * Grid.getSize(), j * Grid.getSize(), "earth");
				//lonely	
				} else {
					if(r.nextInt(101) < j * 7) {
						addBlock(i * Grid.getSize(), j * Grid.getSize(), "earth");
					}
				}
			}
		}
		
		//Polish
		for(int i = minX; i < maxX; i++) {
			for(int j = minY; j < maxY; j++) {
				//left + right
				if(getBlock((i+1) * Grid.getSize(), (j) * Grid.getSize()) != null &&
						getBlock((i-1) * Grid.getSize(), (j) * Grid.getSize()) != null) {
					addBlock(i * Grid.getSize(), j * Grid.getSize(), "earth");
				}
				
				//Grass
				if((getBlock((i) * Grid.getSize(), (j-1) * Grid.getSize()) == null)) {
					if(getBlock(i * Grid.getSize(), j * Grid.getSize()) != null) {
						addBlock(i * Grid.getSize(), j * Grid.getSize(), "grass");
					}
				}
				
				if(r.nextInt(100) <= stoneChance) {
					if(getBlock((i) * Grid.getSize(), (j) * Grid.getSize()) != null && !getBlock((i) * Grid.getSize(), (j) * Grid.getSize()).getType().equals("grass"))
						addBlock(i * Grid.getSize(), j * Grid.getSize(), "stone");
				}
			}
		}
	}
	
	public static Item getItemByIndex(int index) {
		return itemList.get(index);
	}
	
	public static void addItemByIndex(int index, Item item) {
		itemList.add(index, item);
	}
	
	public static void removeItemByIndex(int index) {
		itemList.remove(index);
	}
	
	public static int getItemListSize() {
		return itemList.size();
	}
	
	public static NPC getNPCByIndex(int index) {
		return npcList.get(index);
	}
	
	public static void addNPC(NPC npc) {
		npcList.add(npc);
	}
	
	public static void removeNPCByIndex(int index) {
		npcList.remove(index);
	}
	
	public static int getNPCListSize() {
		return npcList.size();
	}

	public static int getMinX() {
		return minX;
	}

	public static int getMaxX() {
		return maxX;
	}

	public static int getMinY() {
		return minY;
	}

	public static int getMaxY() {
		return maxY;
	}
	
	public static int getItemIndexCounter() {
		return itemIndexCounter;
	}

	public static void setItemIndexCounter(int itemIndexCounter) {
		Map.itemIndexCounter = itemIndexCounter;
	}
}
